/*
 * SyncResource.java
 *
 * Created on April 12, 2007, 1:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.auth.service.app;

import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.client.XMLRepresentationParser;
import org.atomojo.auth.service.db.AuthDB;
import org.atomojo.auth.service.db.Group;
import org.atomojo.auth.service.db.Realm;
import org.atomojo.auth.service.db.RealmUser;
import org.atomojo.auth.service.db.Role;
import org.atomojo.auth.service.db.User;
import org.atomojo.auth.service.db.XML;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.util.DocumentDestination;
import org.restlet.Request;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;

/**
 *
 * @author alex
 */
public class GroupResource extends ServerResource
{
   
   static String ROLE_FACET = "roles";
   static String USER_FACET = "users";
   AuthDB db;
   XMLRepresentationParser parser = XML.createParser();
   Realm realm;
   String facet;
   String facetId;
   String facetName;
   String alias;
   String suuid;
   /** Creates a new instance of SyncResource */
   public GroupResource() {
      setNegotiated(false);
   }

   protected void doInit() {
      db = (AuthDB)getRequest().getAttributes().get(AuthApplication.DB_ATTR);
      parser.addAllowedElement(XML.USER_NAME);
      parser.addAllowedElement(XML.ROLE_NAME);
      realm = null;
      alias = AuthApplication.getStringAttribute(getRequest(),"group-alias",null);
      suuid = AuthApplication.getStringAttribute(getRequest(),"group-id",null);
      facet = AuthApplication.getStringAttribute(getRequest(),"facet",null);
      facetId = AuthApplication.getStringAttribute(getRequest(),"facet-id",null);
      facetName = AuthApplication.getStringAttribute(getRequest(),"facet-name",null);
      realm = (Realm)getRequest().getAttributes().get(AuthApplication.REALM_ATTR);
   }
   
   public Representation get()
   {
      try {
         Group group = fetch();
         if (group!=null) {
            if (facet!=null) {
               if (facet.equals(USER_FACET)) {
                  if (facetId!=null) {
                     try {
                        UUID id = UUID.fromString(facetId);
                        User user = db.getUser(id);
                        if (user!=null) {
                           Representation entity = new DBObjectRepresentation(MediaType.APPLICATION_XML,user);
                           entity.setCharacterSet(CharacterSet.UTF_8);
                           return entity;
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                           return new StringRepresentation("Canot find user by id "+facetId);
                        }
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get user with id "+facetId+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception while processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                  } else if (facetName!=null) {
                     try {
                        User user = db.getUser(facetName);
                        if (user!=null) {
                           Representation entity = new DBObjectRepresentation(MediaType.APPLICATION_XML,user);
                           entity.setCharacterSet(CharacterSet.UTF_8);
                           return entity;
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                           return new StringRepresentation("Cannot find user by alias "+facetName);
                        }
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get user with alias "+facetName+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     }
                  } else {
                     try {
                        Representation entity = new DBIteratorRepresentation(MediaType.APPLICATION_XML,XML.USERS_NAME,group.getMembers());
                        entity.setCharacterSet(CharacterSet.UTF_8);
                        return entity;
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get users from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     }
                  }
               } else if (facet.equals(ROLE_FACET)) {
                  if (facetId!=null) {
                     try {
                        UUID id = UUID.fromString(facetId);
                        Role role = db.getRole(id);
                        if (role!=null) {
                           Representation entity = new DBObjectRepresentation(MediaType.APPLICATION_XML,role);
                           entity.setCharacterSet(CharacterSet.UTF_8);
                           return entity;
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                           return null;
                        }
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get role with id "+facetId+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                     
                  } else if (facetName!=null) {
                     try {
                        Role role = db.getRole(facetName);
                        if (role!=null) {
                           Representation entity = new DBObjectRepresentation(MediaType.APPLICATION_XML,role);
                           entity.setCharacterSet(CharacterSet.UTF_8);
                           return entity;
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                           return null;
                        }
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get role with name "+facetName+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     }
                  } else {
                     Representation entity = new DBIteratorRepresentation(MediaType.APPLICATION_XML,XML.ROLES_NAME,group.getRoles());
                     entity.setCharacterSet(CharacterSet.UTF_8);
                     return entity;
                  }
               } else {
                  getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                  return null;
               }
            } else {
               Representation entity = new DBObjectRepresentation(MediaType.APPLICATION_XML,group);
               entity.setCharacterSet(CharacterSet.UTF_8);
               return entity;
            }
         } else {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get group from database.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      }
   }
   
   public Representation post(Representation entity)
   {
      if (!XMLRepresentationParser.isXML(entity.getMediaType())) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Non-XML media type for entity body: "+entity.getMediaType().getName());
      }
      Document doc = null;
      
      try {
         DocumentDestination dest = new DocumentDestination();
         parser.parse(entity,dest);
         doc = dest.getDocument();
      } catch (Exception ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("XML parse error: "+ex.getMessage());
      }
      
      if (facet==null) {
         getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
         return null;
      }
      
      try {
         Group group = fetch();
         Element top = doc.getDocumentElement();
         if (facet.equals(ROLE_FACET)) {
            if (top.getName().equals(XML.ROLE_NAME)) {
               String sid = top.getAttributeValue("id");
               String name = top.getAttributeValue("name");
               Role role = null;
               if (sid!=null) {
                  role = db.getRole(UUID.fromString(sid));
               }
               if (name!=null && role==null) {
                  role = db.getRole(name);
               }
               if (role==null) {
                  getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                  return new StringRepresentation("Cannot find role "+name);
               } else {
                  group.addRole(role);
                  getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                  return null;
               }
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
               return new StringRepresentation("Element "+top.getName()+" is not allowed.");
            }
         } else if (facet.equals(USER_FACET)) {
            if (top.getName().equals(XML.USER_NAME)) {
               String sid = top.getAttributeValue("id");
               String alias = top.getAttributeValue("alias");
               RealmUser user = null;
               if (sid!=null) {
                  UUID id = UUID.fromString(sid);
                  user = fetchUser(id);
               } else {
                  user = fetchUser(alias);
               }
               if (user==null) {
                  getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                  return new StringRepresentation("Cannot find user.");
               } else {
                  group.addMember(user);
                  getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                  return null;
               }
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
               return new StringRepresentation("Element "+top.getName()+" is not allowed.");
            }
         } else {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Error while adding permission to role.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      } catch (IllegalArgumentException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Bad UUID value: "+facetId);
      }
   }
   
   protected Group fetch()
      throws SQLException
   {
      /*
      if (realm==null) {
         if (realmName!=null) {
            realm = db.getRealm(realmName);
         }
         if (realmId!=null) {
            try {
               UUID id = UUID.fromString(realmId);
               realm = db.getRealm(id);
            } catch (IllegalArgumentException ex) {
               // eat the exception because it is the same as not found
            }
         }
      }
       */
      Group group = null;
      if (realm!=null) {
         if (alias!=null) {
            group = db.getGroup(realm,alias);
         }
         if (suuid!=null) {
            UUID id = UUID.fromString(suuid);
            group = db.getGroup(realm,id);
         }
      }
      return group;
   }
   
   protected RealmUser fetchUser(UUID id) 
      throws SQLException
   {
      /*
      if (realm==null) {
         if (realmName!=null) {
            realm = db.getRealm(realmName);
         }
         if (realmId!=null) {
            try {
               UUID rid = UUID.fromString(realmId);
               realm = db.getRealm(rid);
            } catch (IllegalArgumentException ex) {
               // eat the exception because it is the same as not found
            }
         }
      }
       */
      return db.getRealmUser(realm,id);
   }

   protected RealmUser fetchUser(String alias) 
      throws SQLException
   {
      /*
      if (realm==null) {
         if (realmName!=null) {
            realm = db.getRealm(realmName);
         }
         if (realmId!=null) {
            try {
               UUID id = UUID.fromString(realmId);
               realm = db.getRealm(id);
            } catch (IllegalArgumentException ex) {
               // eat the exception because it is the same as not found
            }
         }
      }
       */
      return db.getRealmUser(realm,alias);
   }
   
   public Representation delete() {
      try {
         Group group = fetch();
         if (group!=null) {
            if (facet!=null) {
               if (facet.equals("members")) {
                  if (facetId!=null) {
                     try {
                        UUID id = UUID.fromString(facetId);
                        RealmUser user = fetchUser(id);
                        if (user!=null && group.removeMember(user)) {
                           getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                        }
                        return null;
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get user with id "+facetId+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                  } else if (facetName!=null) {
                     try {
                        RealmUser user = fetchUser(facetName);
                        if (user!=null && group.removeMember(user)) {
                           getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                        }
                        return null;
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get user with alias "+facetName+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                  } else {
                     getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
                     return null;
                  }
               } else if (facet.equals("roles")) {
                  if (facetId!=null) {
                     try {
                        UUID id = UUID.fromString(facetId);
                        Role role = db.getRole(id);
                        if (role!=null && group.removeRole(role)) {
                           getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                        }
                        return null;
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get role with id "+facetId+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                     
                  } else if (facetName!=null) {
                     try {
                        Role role = db.getRole(facetName);
                        if (role!=null && group.removeRole(role)) {
                           getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                        } else {
                           getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                        }
                        return null;
                     } catch (SQLException ex) {
                        getContext().getLogger().log(Level.SEVERE,"Cannot get role with name "+facetName+" from database.",ex);
                        getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                        return new StringRepresentation("Exception during processing, see logs.");
                     } catch (IllegalArgumentException ex) {
                        getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        return new StringRepresentation("Bad UUID value "+facetId);
                     }
                  } else {
                     getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
                     return null;
                  }
               } else {
                  getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                  return null;
               }
            } else {
               group.delete();
            }
            getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
            return null;
         } else {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
      } catch (IllegalArgumentException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Bad UUID value specified: "+ex.getMessage());
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Database error during group delete: "+ex.getMessage(),ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing, see logs.");
      }
   }
  
}
